package TwentyOne;

/*
 * 使用面向对象的概念表示出下面的生活场景：小明去超市买东西，所有买到的东西都放在了购物车，最后到收银员结账。
 * 
 * 1、定义商品标准
 * 2、定义购物车标准
 * 3、定义一个购物车的实现类
 * 4、定义收银台
 * 5、定义商品信息
 *   图书：
 *   书包：
 * 6、进行代码测试的编写
 */
interface ILink<E> {         //设置泛型避免安全隐患

    public void add(E e);   //增加数据

    public int size();    //获取数据的个数

    public boolean isEmpty();   //判断是否空集合

    public Object[] toArray();     //将集合元素以数组的形式返回

    public E get(int index);   //根据索引获取数据

    public void set(int index, E data);    //修改索引数据

    public boolean contains(E data); //判断数据是否存在

    public void remove(E e);        //数据删除

    public void clean();    //清空集合
}

class LinkImpl<E> implements ILink<E> {

    private class Node {         //保存节点的数据关系

        private E data;      //保存数据
        private Node next;       //保存下一个引用

        public Node(E data) {          //有数据的情况下才有意义
            this.data = data;
        }
        //第一次调用：this = LinkImpl.root ;
        //第二次调用：this = LinkImpl.root.next ;
        //第三次调用：this = LinkImpl.root.next.next ;

        public void addNode(Node newNode) {      //保存新的Node数据
            if (this.next == null) {   //当前节点的下一个节点为null
                this.next = newNode;      //保存当前节点
            } else {
                this.next.addNode(newNode);
            }
        }
        //第一次调用：this = LinkImpl.root
        //第二次调用：this = LinkImpl.root.next
        //第三次调用：this = LinkImpl.root.next.next

        public void toArrayNode() {
            LinkImpl.this.returnData[LinkImpl.this.foot++] = this.data;
            if (this.next != null) {     //还有下一个数据
                this.next.toArrayNode();
            }
        }

        public E getNode(int index) {
            if (LinkImpl.this.foot++ == index) {       //索引相同
                return this.data;    //返回当前数据
            } else {
                return this.next.getNode(index);
            }
        }

        public void setNode(int index, E data) {
            if (LinkImpl.this.foot++ == index) {       //索引相同
                this.data = data;    //修改数据
            } else {
                this.next.setNode(index, data);
            }
        }

        public boolean containsNode(E data) {
            if (data.equals(this.data)) {    //对象比较
                return true;
            } else {
                if (this.next == null) {         //没有后续节点
                    return false;   //找不到
                } else {
                    return this.next.containsNode(data);   //向后继续判断 
                }
            }
        }

        public void removeNode(Node<E> previous, E data) {
            if (this.data.equals(data)) {
                previous.next = this.next;
            } else {
                if (this.next != null) {
                    this.next.removeNode(this, data);
                }
            }
        }

        public void removeNode(Node previous, E data) {
            if (this.data.equals(data)) {
                previous.next = this.next;    //空出当前节点
            } else {
                if (this.next != null) {       //有后续节点
                    this.next.removeNode(this, data);    //向后继续删除
                }
            }
        }
    }
    //------------以下为Link类中定义的成员-----------------
    private Node root;       //保存根元素
    private int count;     //保存数据的个数
    private int foot;     //描述的是操作数组的脚标
    private Object[] returnData;   //返回的数据保存
    //------------以下为Link类中定义的方法-----------------

    public void add(E e) {
        if (e == null) {
            return;
        }
        //数据本身是不具有关联特性的，只有Node类有，要想关联处理就必须将数据包装在Node类中
        Node newNode = new Node(e);    //创建一个新的节点
        if (this.root == null) {            //现在没有根节点
            this.root = newNode;       //第一个节点作为根节点
        } else {                          //根节点存在
            this.root.addNode(newNode);       //将新节点保存在合适的位置
        }
        this.count++;
    }

    public int size() {
        return this.count;
    }

    public boolean isEmpty() {
        //return this.root == null ;
        return this.count == 0;
    }

    public Object[] toArray() {
        if (this.isEmpty()) {           //空集合
            return null;      //现在没有数据
        }
        this.foot = 0;  //脚标清零
        this.returnData = new Object[this.count];   //根据已有的长度开辟数组
        this.root.toArrayNode(); //利用Node类进行递归数据获取
        return this.returnData;
    }

    public E get(int index) {
        if (index >= this.count) {    //索引应该在指定的范围之内
            return null;
        }    //索引数据的获取应该由Node类完成
        this.foot = 0;   //重置索引的下标
        return this.root.getNode(index);
    }

    public void set(int index, E data) {
        if (index >= this.count) {    //索引应该在指定的范围之内
            return;     //方法结束
        }    //索引数据的获取应该由Node类完成
        this.foot = 0;   //重置索引的下标
        this.root.setNode(index, data);  //修改数据
    }

    public boolean contains(E data) {
        if (data == null) {
            return false;     //没有数据
        }
        return this.root.containsNode(data);    //交给Node类判断
    }

    public void remove(E data) {
        if (this.contains(data)) {     //判断数据是否存在
            if (this.root.data.equals(data)) {       //根节点为要删除节点
                this.root = this.root.next;    //根的下一个节点  
            } else {         //交由Node类进行删除
                this.root.next.removeNode(this.root, data);
            }
            this.count--;
        }
    }

    public void clean() {
        this.root = null;  //后续的所有节点都没了
        this.count = 0;   //个数清零
    }
}

interface IGoods {    //定义商品标准

    public String getName();

    public double getPrice();
}

interface IShopCar {       //购物车

    public void add(IGoods goods);   //添加商品信息

    public void delete(IGoods goods); //删除商品

    public Object[] getAll();   //获得购物车中全部商品信息
}

interface ICashier {

    public int getNumber();

    public double getPrice();
}

class ShopCarImpl implements IShopCar {   //购物车

    ILink<IGoods> allGoodseses = new LinkImpl<IGoods>();

    public void add(IGoods goods) {
        this.allGoodseses.add(goods);
    }

    public void delete(IGoods goods) {
        this.allGoodseses.remove(goods);
    }

    public Object[] getAll() {
        return this.allGoodseses.toArray();
    }
}

class Cashier {     //收银台

    private IShopCar shopcar;

    public Cashier(IShopCar shopcar) {
        this.shopcar = shopcar;
    }

    public double allPrice() {    //计算总价
        double all = 0.0;
        Object result[] = this.shopcar.getAll();
        for (Object obj : result) {
            IGoods goods = (IGoods) obj;
            all += goods.getPrice();
        }
        return all;
    }

    public int allCount() {    //商品数量
        return this.shopcar.getAll().length;
    }
}

class Bag implements IGoods {

    private String name;
    private double price;

    public Bag(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return this.name;
    }

    public double getPrice() {
        return this.price;
    }

    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Bag)) {
            return false;
        }
        Bag bag = (Bag) obj;
        return this.name.equals(bag.name) && this.price == bag.price;
    }

    public String toString() {
        return "【背包信息】名称：" + this.name + "、价格：" + this.price;
    }
}

class Book implements IGoods {

    private String name;
    private double price;

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return this.name;
    }

    public double getPrice() {
        return this.price;
    }

    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Book)) {
            return false;
        }
        Book book = (Book) obj;
        return this.name.equals(book.name) && this.price == book.price;
    }

    public String toString() {
        return "【图书信息】名称：" + this.name + "、价格：" + this.price;
    }
}

public class a21_ShopCart {

    public static void main(String args[]) {
        ShopCarImpl car = new ShopCarImpl();
        car.add(new Book("Java开发", 79.8));
        car.add(new Book("Oracle ", 89.8));
        car.add(new Bag("小强背包", 889.8));
        Cashier cas = new Cashier(car);
        System.out.println("总价格：" + cas.allPrice() + "、购买总数量：" + cas.allCount());
    }
}
